#pragma once

#include <stdint.h>
#include <string>


namespace EZWebsocket {
namespace CloseCode {

    /// The type of a close code value.
    typedef uint16_t value;

    /// for internal use.
    static value const http_agin = 1;

    static value const http_error = 2;

    

    /// Normal closure, meaning that the purpose for which the connection was
    /// established has been fulfilled.
    static value const normal = 1000;

    /// The endpoint was "going away", such as a server going down or a browser
    /// navigating away from a page.
    static value const going_away = 1001;

    /// A protocol error occurred.
    static value const protocol_error = 1002;

    /// The connection was terminated because an endpoint received a type of
    /// data it cannot accept.
    /**
    * (e.g., an endpoint that understands only text data MAY send this if it
    * receives a binary message).
    */
    static value const unsupported_data = 1003;

    /// A dummy value to indicate that no status code was received.
    /**
    * This value is illegal on the wire.
    */
    static value const no_status = 1005;

    /// A dummy value to indicate that the connection was closed abnormally.
    /**
    * In such a case there was no close frame to extract a value from. This
    * value is illegal on the wire.
    */
    static value const abnormal_close = 1006;

    /// An endpoint received message data inconsistent with its type.
    /**
    * For example: Invalid UTF8 bytes in a text message.
    */
    static value const invalid_payload = 1007;

    /// An endpoint received a message that violated its policy.
    /**
    * This is a generic status code that can be returned when there is no other
    * more suitable status code (e.g., 1003 or 1009) or if there is a need to
    * hide specific details about the policy.
    */
    static value const policy_violation = 1008;

    /// An endpoint received a message too large to process.
    static value const message_too_big = 1009;

    /// A client expected the server to accept a required extension request
    /**
    * The list of extensions that are needed SHOULD appear in the /reason/ part
    * of the Close frame. Note that this status code is not used by the server,
    * because it can fail the WebSocket handshake instead.
    */
    static value const extension_required = 1010;

    /// An endpoint encountered an unexpected condition that prevented it from
    /// fulfilling the request.
    static value const internal_endpoint_error = 1011;

    /// Indicates that the service is restarted. A client may reconnect and if
    /// if it chooses to do so, should reconnect using a randomized delay of
    /// 5-30s
    static value const service_restart = 1012;

    /// Indicates that the service is experiencing overload. A client should
    /// only connect to a different IP (when there are multiple for the target)
    /// or reconnect to the same IP upon user action.
    static value const try_again_later = 1013;

    /// An endpoint failed to perform a TLS handshake
    /**
    * Designated for use in applications expecting a status code to indicate
    * that the connection was closed due to a failure to perform a TLS
    * handshake (e.g., the server certificate can't be verified). This value is
    * illegal on the wire.
    */
    static value const tls_handshake = 1015;

    /// A generic subprotocol error
    /**
    * Indicates that a subprotocol error occurred. Typically this involves
    * receiving a message that is not formatted as a valid message for the
    * subprotocol in use.
    */
    static value const subprotocol_error = 3000;

    /// A invalid subprotocol data
    /**
    * Indicates that data was received that violated the specification of the
    * subprotocol in use.
    */
    static value const invalid_subprotocol_data = 3001;

    /// First value in range reserved for future protocol use
    static value const rsv_start = 1016;
    /// Last value in range reserved for future protocol use
    static value const rsv_end = 2999;

    inline std::string get_string(value code) {
        switch (code) {
        case normal:
            return "Normal close";
        case going_away:
            return "Going away";
        case protocol_error:
            return "Protocol error";
        case unsupported_data:
            return "Unsupported data";
        case no_status:
            return "No status set";
        case abnormal_close:
            return "Abnormal close";
        case invalid_payload:
            return "Invalid payload";
        case policy_violation:
            return "Policy violoation";
        case message_too_big:
            return "Message too big";
        case extension_required:
            return "Extension required";
        case internal_endpoint_error:
            return "Internal endpoint error";
        case tls_handshake:
            return "TLS handshake failure";
        case subprotocol_error:
            return "Generic subprotocol error";
        case invalid_subprotocol_data:
            return "Invalid subprotocol data";
        default:
            return "Unknown";
        }
    }
}
}